﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using MetroGA.Core;
using MetroGA.Core.Hits;
using Newtonsoft.Json;
using Windows.Storage;

namespace MetroGA.Win8.Lib
{
	internal class Analytics : AnalyticsCore
	{
		private const string StoreFilename = "metroga.store";

		private Mutex FileAccessMutex { get { return new Mutex(true, ApplicationId + ".MetroGA"); } }

		public Analytics(string trackerId, string applicationId, string applicationName, string applicationVersion)
			: base(new InformationProvider(), new SessionContainer(), trackerId, applicationId, applicationName, applicationVersion)
		{
			Initialize();
		}

		protected override Task<bool> SendHit(Hit hit)
		{
			var client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip });
			client.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue { NoCache = true, NoStore = true, NoTransform = true };
			client.DefaultRequestHeaders.Pragma.Add(new NameValueHeaderValue("no-cache"));
			client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(hit.ApplicationName, hit.ApplicationVersion));
			{
				var comment = String.Format("({0}; U; {1}; {2})", InformationProvider.PlatformName, InformationProvider.PlatformVersion, InformationProvider.Culture);
				client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(comment));
			}

			return client.PostAsync(AnalyticsBaseUri, new FormUrlEncodedContent(hit.ToKeyValuePairs()))
						 .ContinueWith(t =>
							 {
								 Debug.WriteLine(t.Result.StatusCode);
								 return (int)t.Result.StatusCode < 400;
							 });
		}

		protected override async Task<IEnumerable<Hit>> LoadPersistedHitsAsync()
		{
			var content = string.Empty;
			if (await ApplicationData.Current.TemporaryFolder.FileExists(StoreFilename))
			{
				content = await FileIO.ReadTextAsync(await ApplicationData.Current.TemporaryFolder.GetFileAsync(StoreFilename));
			}
			
			return JsonConvert.DeserializeObject<IEnumerable<Hit>>(content,
																   new JsonSerializerSettings
																	   {
																		   TypeNameHandling = TypeNameHandling.Objects,
																		   Binder = new HitTypeBinder(),
																		   ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
																	   })
				   ?? Enumerable.Empty<Hit>();
		}

		protected override void PersistHits(IEnumerable<Hit> hits)
		{
			try
			{
				JsonConvert.SerializeObjectAsync(hits,
				                                 Formatting.None,
				                                 new JsonSerializerSettings
					                                 {
						                                 Binder = new HitTypeBinder(),
						                                 TypeNameHandling = TypeNameHandling.Objects,
					                                 })
				           .ContinueWith<Task>(async t =>
					           {
						           var content = t.Result;
						           var storeFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync(StoreFilename, CreationCollisionOption.ReplaceExisting);
						           await FileIO.WriteTextAsync(storeFile, content);
					           })
				           .Wait();
			}
			catch (Exception)
			{
			}
		}
	}
}